<?php


namespace app\api\controller\v14;


use app\api\controller\v13\Auth2;
use app\common\cachemodel\AppConfig;
use app\common\lib\Aes;
use app\common\lib\Alidayu;
use app\common\lib\exception\ApiException;
use app\common\lib\IAuth;
use app\common\lib\SensorsData;
use app\common\lib\Util;
use app\common\model\AppTelLogin;
use app\common\model\User;
use app\common\model\UserPush;
use think\Cache;
use think\Db;
use think\Exception;
use think\Log;
use think\response\Json;

class Login extends Auth2
{
    /**
     * 获取手机验证码
     * @return Json
     * @throws \Exception
     */
    public function getCode()
    {
        $distinctId = $this->request->header('distinct-id', '');
        $sensorsTrackData = [
            'code_type' => '登录',//  登录，注册，绑定、注销、临时绑定
            'is_success' => true,
            'failed_reson' => '',
        ];
        $type = input('type/d', 0);
        $tel = input('tel/s', '');// 账号注销时，手机号为空
        if (Util::CheckAppVersion('2.6.0') !== '小')
        {
            $aesType = $this->headers['app-type'] === 'harmonyos' ? 'harmonyos' : 'app';
            $tel = (new Aes())->decryptWithOpenssl($tel, $aesType);
        }
        $areaCode = input('area_code/d', 86);

        // 1=>登录，2=>绑定，3=>注销
        switch ($type)
        {
            case 1:
                $sensorsTrackData['code_type'] = '登录';
                // 检查手机号是否正确
                if (!$tel || !Util::telRuleCheck($tel, $areaCode))
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '手机号错误';
                    #神策打点 4  获取验证码
                    if ($distinctId !== '')
                    {
                        SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                    }
                    return show(config('code.error'), '手机号错误');
                }
                /**
                 * 过滤非法获取验证码请求，直接返回发送成功
                 */
                if (Util::isIllegalRequest(true))
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '非法获取验证码';
                    #神策打点 4  获取验证码
                    if ($distinctId !== '')
                    {
                        SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                    }
                    return show(config('code.success'), '发送成功');
                }
                try
                {
                    $user = (new User)->where(['tel' => $tel])->findOrFail();
                }
                catch (Exception $e)
                {
                    $user = [];
                }
                if (empty($user))
                {
                    $sensorsTrackData['code_type'] = '注册';
                }
                break;
            case 2:
                $sensorsTrackData['code_type'] = '绑定';
                // 检验手机号是否注册过，未注册过通过
                if (!$tel || !Util::telRuleCheck($tel, $areaCode))
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '手机号错误';
                    #神策打点 4  获取验证码
                    if ($distinctId !== '')
                    {
                        SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                    }
                    return show(config('code.error'), '手机号错误');
                }
                if (!$this->user)
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '登录失效';
                    #神策打点 4  获取验证码
                    if ($distinctId !== '')
                    {
                        SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                    }
                    return show(config('code.denied'), '登录失效');
                }
                try
                {
                    $user = (new User)->where(['tel' => $tel])->findOrFail();
                }
                catch (Exception $e)
                {
                    $user = [];
                }
                if (!empty($user))
                {
                    // 2.5.0以后版本允许发送验证码
                    if (Util::CheckAppVersion('2.5.0') === '小')
                    {
                        $sensorsTrackData['is_success'] = false;
                        $sensorsTrackData['failed_reson'] = '此手机号已注册，请使用此手机号登录或注销此手机号重新绑定';
                        #神策打点 4  获取验证码
                        if ($distinctId !== '')
                        {
                            SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                        }
                        return show(config('code.error'), '此手机号已注册，请使用此手机号登录或注销此手机号重新绑定');
                    } else
                    {
                        $sensorsTrackData['code_type'] = '临时绑定';
                    }
                }
                break;
            case 3:
                $sensorsTrackData['code_type'] = '注销';
                // 服务器获取手机号，若有则通过
                if (!$this->user)
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '登录失效';
                    #神策打点 4  获取验证码
                    if ($distinctId !== '')
                    {
                        SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                    }
                    return show(config('code.denied'), '登录失效');
                }

                if ($this->user['tel'])
                {
                    $telData = explode('-', $this->user['tel']);
                    if (count($telData) > 1)
                    {
                        [$areaCode, $tel] = $telData;
                    } else
                    {
                        $areaCode = 86;
                        $tel = $this->user['tel'];
                    }
                } else
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '未绑定手机号，无法通过手机号注销';
                    #神策打点 4  获取验证码
                    if ($distinctId !== '')
                    {
                        SensorsData::track($this->user['id'], true, 'PhoneVerify', $sensorsTrackData);
                    }
                    return show(config('code.error'), '您未绑定手机号');
                }
                break;
            default:
                $sensorsTrackData['is_success'] = false;
                $sensorsTrackData['failed_reson'] = '未知的验证码类型';
                #神策打点 4  获取验证码
                if ($distinctId !== '')
                {
                    SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                }
                return show(config('code.error'), '未知的登录方式');
                break;
        }

        $telStr = 'isSend:' . $areaCode . '-' . $tel;
        $isSendCode = Cache::get($telStr, false);
        if ($isSendCode)
        {
            return show(config('code.error'), '操作频繁，请稍后再试～');
        }

        $time = time();// 当前时间  有效时间暂定为十分钟 600s

        $expire = 600;

        $ip = $this->request->ip();

        try
        {
            $data = (new AppTelLogin())->where(['tel' => $tel, 'expire_time' => ['>', $time]])->findOrFail()->toArray();
        }
        catch (\Exception $e)
        {
            $data = [];
        }
        // 十分钟内无已有验证码
        if (empty($data))
        {
            $code = random_int(100000, 999999);// 六位验证码

            $expire_time = $time + $expire;
            try
            {
                Db::table('app_tel_login')->insertGetId([
                    'tel' => "$tel",
                    'create_time' => $time,
                    'expire_time' => $expire_time,
                    'code' => $code,
                ]);
            }
            catch (\Exception $e)
            {
                $sensorsTrackData['is_success'] = false;
                $sensorsTrackData['failed_reson'] = '验证码入库失败';
                #神策打点 4  获取验证码
                if ($distinctId !== '')
                {
                    SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
                }
                Log::write('获取手机验证码失败：' . $e->getMessage() . PHP_EOL . '失败行数：' . $e->getLine() . PHP_EOL . '错误文件：【' . $e->getFile() . '】');
                return show(config('code.error'), '发送失败');
            }

        } else
        {
            $code = $data['code'];
        }
        $alidayu = (new AppConfig())->configInfo('alidayu');
        // 短信模板ID 配置KEY
        if ($type === 3)
        {// 注销
            $smsIdConfigKey = $areaCode === 86 ? 'logout_code' : 'abroad_logout_code';
        } else
        {// 登录或绑定
            $smsIdConfigKey = $areaCode === 86 ? 'login_code' : 'abroad_login_code';
        }
        if ((int)$areaCode === 1)
        {
            $result = Alidayu::getInstance()->sendSmsUSA($tel, $code, $smsIdConfigKey);
        } else
        {
            $result = Alidayu::getInstance()->sendSms($tel, $code, $alidayu[$smsIdConfigKey], $areaCode);
        }
        if (!$result)
        {
            return show(config('code.error'), '发送失败');
        }
        Cache::set($telStr, true, 50);
        Cache::set($this->user['id'] . 'logout', $code, 600);
        // 记录短信日志
        model('log')->save([
            'tel' => "$tel",
            'ip' => $ip,
            'create_time' => $time,
            'type' => $type,
        ]);
        #神策打点 4  获取验证码
        if ($distinctId !== '')
        {
            // 若
            $distinctId = $this->user['id'] ?: $distinctId;
            SensorsData::track($distinctId, false, 'PhoneVerify', $sensorsTrackData);
        }
        return show(config('code.success'), '发送成功');
    }

    /**
     * @title 手机验证码登录
     * @method POST
     * @return Json
     * @throws ApiException
     */
    public function mobile()
    {
        #神策打点 5   登录成功
        $sensorsTrackData = [
            'is_register' => false,
            'login_type' => '手机号',// 手机号、微信、QQ、微博、AppleID、手机号一键登录
            'is_temporary' => false,// 三方登录时，需要设置这个属性
            'is_success' => true,
            'failed_reson' => '',
        ];
        if (!$this->request->isPost())
        {
            return show(config('code.error'), '未知操作');
        }
        $distinctId = $this->request->header('distinct-id', '');

        $tel = input('tel/s', '');
        if (Util::CheckAppVersion('2.6.0') !== '小')
        {
            $aesType = $this->headers['app-type'] === 'harmonyos' ? 'harmonyos' : 'app';
            $tel = (new Aes())->decryptWithOpenssl($tel, $aesType);
        }
        $code = input('code/s', '');
        $areaCode = input('area_code/d', 86);
        $time = $this->request->time();
        $ip = $this->request->ip();
        $appConfig = config('app');

        // 手机号不可注册
        $user = $this->CheckUserTel($tel, $areaCode);

        // 短信验证码 或 密码是否存在
        if (empty($code))
        {
            if ($distinctId)
            {
                $sensorsTrackData['is_success'] = false;
                $sensorsTrackData['failed_reson'] = '短信验证码未填写';
                SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
            }
            return show(config('code.error'), '手机短信验证码');
        }
        // 短信登录时，检测验证码是否正确
        if (!empty($code))
        {
            if (!in_array($tel, $appConfig['mobile'])
                || ($areaCode === 86 && $code != substr($appConfig['code'] * (substr($tel, 3, 6)), 0, 6)))
            {
                //苹果和安卓应用商店审核账号，固定验证码为666666
                if (($tel == '13045794520' && $code == '666666')
                    || ($tel == '13261877781' && $code == '666666'))
                {

                } else
                {
                    //  validate 严格校验
                    $mobileCode = Alidayu::getInstance()->checkSmsIdentify($tel, $areaCode);

                    if ($code != $mobileCode)
                    {
                        if ($distinctId)
                        {
                            $sensorsTrackData['is_success'] = false;
                            $sensorsTrackData['failed_reson'] = '短信验证码错误';
                            SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
                        }
                        return show(config('code.error'), '短信验证码错误');
                    }
                }
            }
        }
        // 生成token  和 token到期时间
        $token = IAuth::setAppLoginToken($tel);
        $data = [
            'token' => $token,
            'token_expire' => strtotime("+" . $appConfig['login_time_out_day'] . " days"),
        ];
        $UserModel = new User();
        //判断用户是否绑定准了号
        if ($user)
        {
            $UserModel->check_uen($user);
        }

        $nickname = preg_replace('/(1[3456789]{1}[0-9])[0-9]{4}([0-9]{4})/i', '$1****$2', $tel);
        $isRegist = false;
        // 该用户是否正常  forbidden==1 禁止登录
        if ($user && $user['forbidden'] == 0)
        {
            // 已过期重新生成access_token
            if ($time > $user['token_expire'] || !in_array($tel, $appConfig['mobile']))
            {
                $mobileTel = $areaCode === 86 ? $tel : $areaCode . '-' . $tel;
                $UserModel->save($data, ['tel' => $mobileTel]);
            } else
            {
                $token = $user['token'];
            }
//            $UserModel->save($data, ['tel' => $tel]);
            if (!$user['nickname'])
            {
                try
                {
                    Db::table('app_user')->where('tel', $tel)
                        ->update(['nickname' => $nickname]);
                }
                catch (Exception $e)
                {
                    Log::write('手机验证码登陆时初始化用户昵称失败' . $e->getMessage(), true);
                }
            }
        } elseif ($user && $user['forbidden'] == 1)
        {
            if ($distinctId)
            {
                $sensorsTrackData['is_success'] = false;
                $sensorsTrackData['failed_reson'] = '该账号禁止登录';
                SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
            }
            return show(config('code.error'), '该账号禁止登录');
        } //手机号不可注册
        elseif (!$user && !empty($code) && !empty($tel))
        {
            $sensorsTrackData['is_register'] = true;
            $checkResult = Util::registCheckLogoutCD(['tel' => $tel]);
            if (!$checkResult['result'])
            {
                if ($distinctId)
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '账号注销时间不足，注册失败';
                    SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
                }
                throw new ApiException($checkResult['msg'], 200, config('code.error'));
            }
            $isRegist = true;
            // 第一次登录 注册数据
            $user['uen'] = substr(md5($this->request->time(true) . mt_rand(0, 1000000) . uniqid()), 0, 12);
            $user['nickname'] = $nickname;
            $user['reg_time'] = $time;
            $user['reg_ip'] = $ip;
            $user['last_login'] = $time;
            $user['last_ip'] = $ip;
            $user['last_active'] = $time;
            $user['status'] = 1;
            $user['sex'] = 1;
            $user['tel'] = $areaCode === 86 ? $tel : $areaCode . '-' . $tel; // 国内手机号不拼接国际手机区号
            $user['is_first_login'] = 1;
            $user['uc_id'] = md5($tel . $this->request->time(true));
            $user['token'] = $data['token'];
            $user['token_expire'] = $data['token_expire'];
            $user['has_self_recode'] = 0;
            $user['channel'] = Util::getChannelId();
            try
            {
                $user['id'] = $UserModel->insertGetId($user);
                Cache::set('user_total_amount_' . $user['id'], 0, 86400);// 消费金额为0
                // 记录注册日志
                Util::logRealTimeAnalyzeWrite(1, [
                    'user_uid' => $user['id'],
                    'user_name' => $tel,
                    'user_sex' => 0,
                    'user_reg_type' => 4,//1微信 2QQ 3微博 4手机号 5一键登录
                    'user_ip' => $ip,
                ]);
            }
            catch (\Exception $e)
            {
                if ($distinctId)
                {
                    $sensorsTrackData['is_success'] = false;
                    $sensorsTrackData['failed_reson'] = '注册失败，请稍后重试';
                    SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
                }
                return show(config('code.error'), '注册失败,请稍后重试');
            }
            if ($distinctId)
            {
                // 用户完成手机号注册时，更新用户属性
                $userData = [
                    'user_resgistration_time' => date('Y-m-d H:i:s', $user['reg_time']),
                    'user_uen' => $user['uen'],
                    'user_phone_num' => $user['tel'],
                    'user_is_vip' => false,
                    'user_vip_level' => 0,
                    'user_star_num' => 0,
                ];
                SensorsData::profile($user['id'], true, $userData, 'set');
            }

            // 判断用户 APP版本大于等于 2.4.0 赠送 新手礼包
            if (Util::CheckAppVersion('2.4.0') !== '小')
            {   // 不小于 2.4.0
                Util::queuePush('register_package', ['uid' => (int)$user['id']], 0);
            }

            try
            {
                $msg = Db::table('app_message_center')->field('id')->where('range', 0)->select();
            }
            catch (\Exception $e)
            {
                Log::write('获取系统消息失败' . $e->getMessage(), true);
            }
            if (isset($msg) && !empty($msg))
            {
                foreach ($msg as $k => $v)
                {
                    Db::table('app_user_msg')->insert(['uid' => $user['id'], 'mid' => $v['id']]);
                }
            }
        }

        if ($user)
        {
            $id = (int)($user['id']);

            if (!$isRegist)
            {
                $userPush = (new UserPush())->getUserRegid($id);
                $calendarBirthdayStatus = (int)($userPush['calendar_birthday_status'] ?? 0);
                $recodePrivateStatus = (int)($userPush['recode_private_status'] ?? 0);
                $isLoginRecord = 1;
            } else
            {
                $calendarBirthdayStatus = 1;
                $recodePrivateStatus = 1;
                $isLoginRecord = (int)($user['is_login_record'] ?? 1);  // 是否记录设备登陆历史 1=>记录，2=>不记录
            }

            if (isset($user['young_pwd']))
            {
                $isYoung = $user['young_pwd'] ? true : false;
            } else
            {
                $isYoung = false;
            }

            // 记录登陆设备日志
            Util::loginRecordSave($id, 4, $isLoginRecord, $ip);

            $result = [
                'id' => $id,
                'has_self_recode' => $user['has_self_recode'],
                'user_access_token' => (new Aes())->encryptWithOpenssl($token . "||" . $user['id']),
                'uc_id' => $user['uc_id'],
                'calendar_birthday_status' => $calendarBirthdayStatus ?: 1,   // 在天象日历中展示生日信息
                'recode_private_status' => $recodePrivateStatus ?: 1,   // 在星盘中展示档案详细信息
                'has_bind_tel' => 1,     // 是否绑定了手机号 1绑定了 0未绑定
                'is_young_model' => $isYoung ? 1 : 2,
            ];
            // 记录登陆日志
            Db::table('app_login_log')->insertGetId([
                'uid' => $id,
                'login_time' => $time,
                'login_type' => 4,
                'login_ip' => $ip,
            ]);
            if ($distinctId)
            {
                // 神策打点，用户关联
                SensorsData::signup($id, $distinctId);
                SensorsData::track($id, true, 'LoginSuccess', $sensorsTrackData);
            }
            return show(config('code.success'), 'ok', $result);
        }
        if ($distinctId)
        {
            SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
        }
        return show(config('code.error'), '登录失败');
    }

    /**
     * 检测手机号格式，不可注册
     * @param $tel
     * @param int $areaCode 手机区号
     * @return array
     * @throws ApiException
     */
    public function CheckUserTel($tel, $areaCode = 86)
    {
        // 手机号是否存在
        if (!Util::telRuleCheck($tel, $areaCode))
        {
            Log::write($areaCode . $tel . '手机号错误', 'error');
            $distinctId = $this->request->header('distinct-id', '');
            if ($distinctId)
            {
                #神策打点 5   登录成功
                $sensorsTrackData = [
                    'is_register' => false,
                    'login_type' => '手机号',// 手机号、微信、QQ、微博、AppleID、手机号一键登录
                    'is_temporary' => false,// 三方登录时，需要设置这个属性
                    'is_success' => false,
                    'failed_reson' => '手机号错误',
                ];
                SensorsData::track($distinctId, false, 'LoginSuccess', $sensorsTrackData);
            }

            throw new ApiException('手机号错误', 200, 0);
        }
        //判断手机号是否注册过
        try
        {
            $tel = $areaCode === 86 ? $tel : $areaCode . '-' . $tel;

            $user = (new \app\common\cachemodel\User())
                ->field('id,forbidden,has_self_recode,password,young_pwd,nickname,uc_id,avatar,token_expire,token,uen,is_login_record')
                ->where(['tel' => $tel])->findOrFail()->toArray();
        }
        catch (Exception $e)
        {
            $user = [];
            // throw new ApiException('手机号未注册，请用三方登录', 200, 409);
        }
        return $user;
    }
}
